{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Deep Reinfocement Learning - Evolution Strategies - Chapter 5"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import random\n",
    "from matplotlib import pyplot as plt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "alphabet = \"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ,.! \"\n",
    "target = \"Hello World!\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Individual:\n",
    "    def __init__(self, string, fitness=0):\n",
    "        self.string = string\n",
    "        self.fitness = fitness"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from difflib import SequenceMatcher\n",
    "\n",
    "def similar(a, b):\n",
    "    return SequenceMatcher(None, a, b).ratio()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def spawn_population(length=26,size=100):\n",
    "    pop = []\n",
    "    for i in range(size):\n",
    "        string = ''.join(random.choices(alphabet,k=length))\n",
    "        individual = Individual(string)\n",
    "        pop.append(individual)\n",
    "    return pop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def mutate(x, mut_rate=0.01):\n",
    "    new_x_ = []\n",
    "    for char in x.string:\n",
    "        if random.random() < mut_rate:\n",
    "            new_x_.extend(random.choices(alphabet,k=1))\n",
    "        else:\n",
    "            new_x_.append(char)\n",
    "    new_x = Individual(''.join(new_x_))\n",
    "    return new_x"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def recombine(p1_, p2_): #produces two children from two parents\n",
    "    p1 = p1_.string\n",
    "    p2 = p2_.string\n",
    "    child1 = []\n",
    "    child2 = []\n",
    "    cross_pt = random.randint(0,len(p1))\n",
    "    child1.extend(p1[0:cross_pt])\n",
    "    child1.extend(p2[cross_pt:])\n",
    "    child2.extend(p2[0:cross_pt])\n",
    "    child2.extend(p1[cross_pt:])\n",
    "    c1 = Individual(''.join(child1))\n",
    "    c2 = Individual(''.join(child2))\n",
    "    return c1, c2"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "def evaluate_population(pop, target):\n",
    "    avg_fit = 0\n",
    "    for i in range(len(pop)):\n",
    "        fit = similar(pop[i].string, target)\n",
    "        pop[i].fitness = fit\n",
    "        avg_fit += fit\n",
    "    avg_fit /= len(pop)\n",
    "    return pop, avg_fit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "def next_generation(pop, size=100, length=26, mut_rate=0.01):\n",
    "    new_pop = []\n",
    "    while len(new_pop) < size:\n",
    "        parents = random.choices(pop,k=2, weights=[x.fitness for x in pop])\n",
    "        offspring_ = recombine(parents[0],parents[1])\n",
    "        offspring = [mutate(offspring_[0], mut_rate=mut_rate), mutate(offspring_[1], mut_rate=mut_rate)]\n",
    "        new_pop.extend(offspring) #add offspring to next generation\n",
    "    return new_pop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "pop = spawn_population(length=len(target))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.11083333333333341\n"
     ]
    }
   ],
   "source": [
    "pop, avg_fit = evaluate_population(pop, target)\n",
    "print(avg_fit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "new_pop = next_generation(pop, length=len(target))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "new_pop[10].fitness"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "num_generations = 100\n",
    "population_size = 3000\n",
    "str_len = len(target)\n",
    "mutation_rate = 0.001 # 0.1% mutation rate per character"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "pop_fit = []\n",
    "pop = spawn_population(size=population_size, length=str_len) #initial population\n",
    "for gen in range(num_generations):\n",
    "    # trainning\n",
    "    pop, avg_fit = evaluate_population(pop, target)\n",
    "    pop_fit.append(avg_fit) #record population average fitness\n",
    "    new_pop = next_generation(pop, size=population_size, length=str_len, mut_rate=mutation_rate)\n",
    "    pop = new_pop"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[<matplotlib.lines.Line2D at 0x7f850a2e9150>]"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAA04AAAHACAYAAACVhTgAAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/H5lhTAAAACXBIWXMAAA9hAAAPYQGoP6dpAABYr0lEQVR4nO3dd3hUZeL28Xtmkkx6IT0hEHqRnkB+gHU3imVZ2yoqCqJrRVfN6goWsLwaLKuosGB3F1dFXXQVBUsUFUWCobdQQ0JJIySTPsnMef+IRrOUhBByUr6f65orzJnnTO7ZPRfM7TnneSyGYRgCAAAAAByV1ewAAAAAANDWUZwAAAAAoBEUJwAAAABoBMUJAAAAABpBcQIAAACARlCcAAAAAKARFCcAAAAAaATFCQAAAAAa4WF2gNbmdru1f/9+BQQEyGKxmB0HAAAAgEkMw1BpaaliYmJktR77nFKnK0779+9XXFyc2TEAAAAAtBE5OTnq2rXrMcd0uuIUEBAgqe5/nMDAQJPTAAAAADCLw+FQXFxcfUc4lk5XnH65PC8wMJDiBAAAAKBJt/AwOQQAAAAANILiBAAAAACNoDgBAAAAQCMoTgAAAADQCIoTAAAAADSC4gQAAAAAjaA4AQAAAEAjKE4AAAAA0AiKEwAAAAA0guIEAAAAAI2gOAEAAABAIyhOAAAAANAIihMAAAAANMLD7AAAAAAA2jfDMFRY5lR2Ubn2HKxQdlGFiitqVFXjUmWNS5XOup+/ff7B1LEK9PY0O3qTUZwAAAAANKrW5db+4irt+U052nOw7s85RRUqd7qO6/0qnS6KEwAAAID2xeU2lF9apX2HKrWv+OfHocqfC1KF9hVXyuU2jrq/xSLFBPmoWxdfdQ/1Vai/l3y9POTtaZOPp00+XlZ5e9jk7VX3PMin/ZQmieIEAAAAdAqlVTU6UFKlfcWV2l9cqQPFVdpf/GtJyi2pUu0xipEkeXlY64pRF1/FdfFVfKivuof6qVuor7qG+MjuYWulT9P6KE4AAABAO/bLJXQ5hyqUX1qlgtJq5TuqlV9aXffn0irll1artKq20ffysFoUFeStmGAfdQ32UWyIj+JCfNUttO4sUmSAt6xWSyt8qraH4gQAAAC0YYZhqKSyRrmOujNEWYV19xZl/XyfUU5RRaNnin4R5OOp6CBvxQb7KCbYR9HBdX/+5XlkoLdsnbQYNYbiBAAAAJik1uVWQVm1DpRUKfeXh+PXn3k/P6pq3Md8H7uHVV1D6opPRIBd4QF2RQR4//yz7nl0sI/87Xz9by7+lwMAAABagGEYcrrcqnK6VVFTq5LKGh0sc6qwrFpF5U4dLHPqYLlTB8vqLqPLLalSfmmVmniySCG+nooK8qm/r6j+Z1jnvoSutVCcAAAAgGNw1rq1v7hudrlfLo3LLqpQzqEKOSprG6xTdKxZ547Gw2pRZKC3ooJ+fgTWPSJ/8+eIQLu8PTvuxAvtAcUJAAAAnZ5hGMovrdbO/DLtLCjTzoJy7Swo066Cch0oqWzyWaFf2KwWBfl4KtTPS6H+Xgr1s9f/7OLvpXB/u2KC60pRqL+d+4raAYoTAAAAOpWDZdXKzC3VltxSbT3gUGZeqXYVlKus+uizznl71k3D3e3nabi7dfFVXIivQvy85ONpk6+XTT5etvo1i7w8rK34idAaKE4AAABodwzDkKOqVvt/XpNof0mVDpZVyzAk49dB9eMrnC5l5pUqM7dU+aXVR3xPq0Xq1sVXvcL91SvCX73C/dQz3F/dQ30V7m+XxcJZoc6M4gQAAADTVDjrys/eQ5X1C7OWVNbI5TZ+fkhuw1Ct25Dbbais+teyVO50Nfv3dg/1Vb/IAPWPDlT/qAD1ifBXt1DfDr2AK04MxQkAAAAnlWEYynVUafN+h7YccGjLgVLtKSrXvkOVOlRRc0Lv3cXPSzHB3ooJ8lFYgF22n88K/fbkkEWSh82qXuH+6h8doH6RAfJjWm4cJ44YAAAANFml06U9ReXKKixXTlGlnC63rBaLbFbJarHIYrHI9nNpyS6qrCtKuQ4VH6MgBdg9FBtStwhrbIiPQny95GG1yGq1yGa1yGb5+afVIh9Pm2KCfRQT7K3oIB/5eHGGCK2D4gQAAIB6tS638kurtb+47tK5vYcqlX2wQlkHy5V1sFx5jiPfH9QYm9WiXuF+GhAdqAHRgeod7l9XlkJ8FOjt2cKfAmh5FCcAAIBOwlnrVn5plfIcVcpzVCvPUaVcR5XySqq0v7hK+4orleuoanQtoiAfT8WH+al7F1/5eNrkMgy5jbp7kNyG5DIMGYahiABvDYwJ1MDoQPWO8GcdIrRrFCcAAIAOory69uezRBXae6jy50fdn/cdqtTBcmeT3sfDalH0z/cNxQb7qFuor+JD/RQf5qf4UF8F+3qd5E8CtD0UJwAAgDaiutal7IMVKq6sUa2rbla5Wrf755+/zipXUFatgtLfPH5+Xlp19HWIfuFlsyoi0K7IwLrFVyMC7YoK9P75vqG6ohQewIKswP+iOAEAALSyfEeVMvNKtbuwXLsKyut+FpZp36FKNXKVXKOCfDzVNcTn54dv/c9fJlMI8fVkPSKgGShOAAAAJ5HbbWhnQZlWZR3ST1lFWrWnSDlFlUcd72/3UHiAXR7WX2eS86j/aZW3l03h/naFB/zm4W9XRKBdEQF2BTDRAnBSUJwAAABaUKXTpfV7i7U6u1gZe4r0055Dh03FbbVI8WF+6hnmr57hfuoZ5qceYX7qEe6ncH87Z4SANojiBAAA0EyGYSi7qEKrsw9pTXaxVmcf0pYDpYfNSuftadXwuBCNjA9RYnwXDe8WzJkhoJ0xvTjNnTtXTz31lHJzczV06FC98MILGjVq1FHHz549W/PmzVN2drbCwsL0pz/9SampqfL29m7F1AAAoDMoKndqR36Z8hxVyi+tVn5pVYNJGQ6UVKmk8vCFXSMD7RrRLUQJ3euK0ikxgfK0WU34BABaiqnFaeHChUpJSdH8+fOVlJSk2bNna9y4ccrMzFRERMRh49966y1NmzZNr732msaMGaNt27bp2muvlcVi0TPPPGPCJwAAAB1BVY1LO/LLlJlbqq25Dm3NLVVmbqnySxtf7NXTZtEpMUEa0S1EI7oHa3i3EMUEeXO5HdDBWAzDOMG5W5ovKSlJI0eO1Jw5cyRJbrdbcXFxuv322zVt2rTDxt92223asmWL0tLS6rf99a9/1cqVK7V8+fIm/U6Hw6GgoCCVlJQoMDCwZT4IAABo034pRvuKK3WguFL7S6q0v7hSB37+meeoOupsdl1D6qbpDg+om3yh7qd3/fMeYX4s7Aq0U8fTDUw74+R0OpWRkaHp06fXb7NarUpOTtaKFSuOuM+YMWP05ptvKj09XaNGjdKuXbv06aef6pprrjnq76murlZ19a//tcjhcLTchwAAAG1Sda1L63JKtGLnQa3YVajV2cVy1rqPuU+wr6f6RQaof1SA+kcHql9UgPpGBsjfbvqdDQDaANP+JigsLJTL5VJkZGSD7ZGRkdq6desR97nqqqtUWFioU089VYZhqLa2VjfffLPuu+++o/6e1NRUPfzwwy2aHQAAtC2GYWjTfoeWZeZrxa6DythzSFU1DYtSiK+nunXxVUywj6KDfBQT7P3zn73rF33l8joAR9Ou/hPKsmXL9Pjjj+sf//iHkpKStGPHDt1xxx169NFH9eCDDx5xn+nTpyslJaX+ucPhUFxcXGtFBgAAJ9H2vFJ9vP6AFq/br12F5Q1eC/P3UlLPUI3uGar/6xmqXuF+FCMAzWZacQoLC5PNZlNeXl6D7Xl5eYqKijriPg8++KCuueYa/fnPf5YkDR48WOXl5brxxht1//33y2o9fLYau90uu93e8h8AAACYYs/Bci1ef0Afr9uvrbml9dvtHlad0Tdcp/YJ0//1DFWfCH+KEoAWY1px8vLyUkJCgtLS0nTRRRdJqpscIi0tTbfddtsR96moqDisHNlsdTdjmjjHBQAAOEkMw9DeQ5X6aU+RVmUd0k9ZRdqWV1b/uqfNotP7hGv80BglD4zkfiQAJ42pf7ukpKRo8uTJSkxM1KhRozR79myVl5drypQpkqRJkyYpNjZWqampkqTx48frmWee0fDhw+sv1XvwwQc1fvz4+gIFAADarxqXW1sPlOqnPUX6KeuQftpTpDxHwynBbVaLxvQK1fghMRp3SpSCfFlIFsDJZ2pxmjBhggoKCjRjxgzl5uZq2LBhWrp0af2EEdnZ2Q3OMD3wwAOyWCx64IEHtG/fPoWHh2v8+PF67LHHzPoIAADgBBSVO7V6zyGtzj6kjD2HtG5v8WGTOvyyTtLI+BAldO+iUT26qIufl0mJAXRWpq7jZAbWcQIAoPU5qmqUVViu3YXlyiqs0K7CMq3fW6Ld/zOhgyQFentoRPcQjYzvooTuIRraNVg+XlxZAqDltYt1nAAAQMdiGIYKyqq1LbdMW3Md2pZXql0F5co6WK7CMudR9+sd4a8R3YKV0D1ECd1D1DPMX1YrkzoAaFsoTgAAoFn2FVfq++2F2nzAoczcUmXmlaqo/OgFKczfrh5hvuoR5qf4MD8NiArU8G7BCvblsjsAbR/FCQAANImz1q1VWUValpmvZZkF2p5fdtgYi0WKD/VTv8gA9YsKUK8If/UM81P3UF8FeDOJA4D2i+IEAAAaMAxDpdW1yndUKc9RrV2F5fp2W4F+2FGocqerfpzVIo3oFqJhccHqFxWg/lGB6h3hz/1IADokihMAAJ1UYVm1Nu13aOO+Em3PK1Xuz0Upz1Glit8UpN8KD7DrjL7hOrNfuE7rHc5U4AA6DYoTAAAdXHWtS/sOVWpnQbk27S/Rxn0ObdpfogMlVcfcL8DbQ1GB3ooK8lZSjy46s1+EBkYHMnEDgE6J4gQAQAeRVViuVVlFyjlUqb1FFco5VKGcokrllVbpSIuPWCxSjzA/DYoJUv/oAMUG+ygy0FtRgd6KCLTL14uvCQDwC/5GBACgHSuvrtWnGw7ovZ/2Kj2r6KjjfDxt6h7qq1NigjQoNlCDYoM0IDpQ/na+CgBAU/C3JQAA7YxhGFqdXaz3fsrRx+v210/YYLVIifFd1CvcT11DfBXXxVdxIT6K6+KrUD8vWSxcYgcAzUVxAgCgjXO5DWUdLFdmbqk273doycYD2llQXv96fKivLkuM06UjuioqyNvEpADQcVGcAABoQ4rKndp6wKEtuaXKzHVoa26ptuWVqqrG3WCcj6dN5w+O1uWJXTWqRxfOJgHASUZxAgDABDUut3YVlGvLAYe25Dq09UCptuY6lOeoPuJ4H0+b+kYFqH9kgBK6h+i8wVEsKAsArYjiBABAK3G7Df2466D+s3qflm480GAx2d/qHuqrfpEBGhAdqP5RAeofHahuXXxlYxpwADANxQkAgJNse16pFq3Zpw/X7GuwdpK/3UP9o34uSNEB6h8VqH5RAcx0BwBtEH8zAwDQAqprXTpUXqOicqcOVThVVO7UvuJKfbL+gDbsK6kfF+jtoQuGxOjSEbEa0S2ExWQBoJ2gOAEAcJxqXG6l7y7SZ5tytXx7ofJLq1VWXXvU8R5Wi87sF6FLRsTqd/0j5O1pa8W0AICWQHECAKAJqmpc+m57oT7blKsvt+SpuKLmsDE2q0Uhvp4K8fVSF7+6x//1DNUfhkQr1N9uQmoAQEuhOAEAcBQut6FlmflatHqfvs7MV8VvJnPo4uelswdE6uyBkeoZ7qcufl4K9Pbk0jsA6KAoTgAA/I88R5UWrsrRO+nZ2v+byRxigrx1zilROndQlBK7h8jDZjUxJQCgNVGcAABQ3VTh3+0o1Fsr9+jLLflyuQ1JUrCvp/40oqv+OCxGg2ODWGgWADopihMAoFNzuQ29+1OO5i3bqeyiivrto+K76Kqkbjp3UBSTOQAAKE4AgM4rY88hzfxoozbuc0iSArw9dOmIrroqqZv6RgaYnA4A0JZQnAAAnU5+aZVmLdmqRav3SaorTHcm99VVo7rJx4uzSwCAw1GcAACdhrPWrX/+kKXn0rarrLpWFot0eUKc7jm3n8KYLhwAcAwUJwBAh3ewrFrLMgv0j2U7tLOgXJI0NC5Yj/zxFA2NCzY3HACgXaA4AQA6HLfb0Mb9Jfp6a4G+zszXur3FMuomyVOYv5f+dm5//WlEV9ZcAgA0GcUJANCuGYahgrJqZRVWaHdhmVZlHdKyzAIVllU3GDcwOlBnD4zUdaf2UJCPp0lpAQDtFcUJANBuGIahb7cXKmPPIWUVlmv3z4+y6trDxvrbPXRq7zCd1T9cZ/SNUFSQtwmJAQAdBcUJANDmudyGPtlwQP/4eoe25pYe9rrFInUN8VGPMH8NiArQGf3Cldi9i7w8rCakBQB0RBQnAECbVV3r0qLV+/TiNzuVdbBucVo/L5vOGxytPhH+6hHmp57hforr4iu7B9OIAwBOHooTAKDNqXDW6q2V2Xr5u13Kc9TdqxTi66kpY3to8uh4BflyjxIAoHVRnAAAbYaz1q1/r9yjF77aoaJypyQpKtBbN5zeU1eOipOvF/9sAQDMwb9AAADTud2GPl6/X09/nqmcokpJUnyor24+o5cuHhHLZXgAANNRnAAAplq+vVCzlm7Rxn0OSVJEgF13JvfV5Yld5WFjcgcAQNtAcQIAmGLT/hLNWrJV320vlFQ3ffjNZ/TUdaf24JI8AECbw79MAIBWle+o0lOfZer91XtlGJKnzaKJSd11++96K9TfbnY8AACOqE1cAzF37lzFx8fL29tbSUlJSk9PP+rYM888UxaL5bDHBRdc0IqJAQDHq6rGpTlfbdeZTy/Texl1pWn80BilpZyph/54CqUJANCmmX7GaeHChUpJSdH8+fOVlJSk2bNna9y4ccrMzFRERMRh4xctWiSn01n//ODBgxo6dKguu+yy1owNAGgiwzC0eP0BzVqyVfuK6yZ+GBYXrBnjB2pEtxCT0wEA0DQWwzAMMwMkJSVp5MiRmjNnjiTJ7XYrLi5Ot99+u6ZNm9bo/rNnz9aMGTN04MAB+fn5NTre4XAoKChIJSUlCgwMPOH8AICjW5dTrEcWb1bGnkOSpOggb007r7/+ODRGFovF5HQAgM7ueLqBqWecnE6nMjIyNH369PptVqtVycnJWrFiRZPe49VXX9UVV1xx1NJUXV2t6urq+ucOh+PEQgMAjsntNvTt9gK99n2Wvt1WIEny8bTp5jN66cbTe8rHi6nFAQDtj6nFqbCwUC6XS5GRkQ22R0ZGauvWrY3un56ero0bN+rVV1896pjU1FQ9/PDDJ5wVAHBsFc5a/Wf1Pr3x/W7tLCiXJFks0sXDYnXPuf0UHeRjckIAAJrP9HucTsSrr76qwYMHa9SoUUcdM336dKWkpNQ/dzgciouLa414ANAp7Cuu1L9WZOntldlyVNVKqptafMLIOE0eHa9uob4mJwQA4MSZWpzCwsJks9mUl5fXYHteXp6ioqKOuW95ebneeecdPfLII8ccZ7fbZbczUxMAtCTDMJS+u0j/XJGlzzblyeWuu122e6ivrh0Trz8ldFWAt6fJKQEAaDmmFicvLy8lJCQoLS1NF110kaS6ySHS0tJ02223HXPf9957T9XV1br66qtbISkAQJIqnS79d+0+vfFDlrbmltZvH90zVNed2kO/6x8hm5VJHwAAHY/pl+qlpKRo8uTJSkxM1KhRozR79myVl5drypQpkqRJkyYpNjZWqampDfZ79dVXddFFFyk0NNSM2ADQqeQUVejNH/fonVU5KqmskSR5e1p18fBYTRodrwHRzFIKAOjYTC9OEyZMUEFBgWbMmKHc3FwNGzZMS5curZ8wIjs7W1Zrw3V6MzMztXz5cn3++edmRAaATmN3Yblmf7lNH6/br5+vxlPXEB9NGt1dlyfGKdjXy9yAAAC0EtPXcWptrOMEAI3bV1yp57/crvdX762/f+nU3mGaPCaey/EAAB1Gu1nHCQDQtuSXVukfX+/UWyuz5XS5JUln9QvXX8/pp0GxQSanAwDAPBQnAICKyp168dud+ucPWaqqqStMo3uG6u5xfZXQvYvJ6QAAMB/FCQA6sS0HHHr9+936cO1+OWvrCtOwuGDdM66fxvYOMzkdAABtB8UJADoZl9vQl1vy9Pr3u/XjrqL67YNjg3Rnch/9rn+ELBbuYQIA4LcoTgDQSTiqarQwPUf/XJGlvYcqJUk2q0XnnhKlKWPjldA9hMIEAMBRUJwAoINzuQ29sypbT3+WqUMVdWswBft66oqR3TRpdHfFBPuYnBAAgLaP4gQAHdjKXQf10MebteWAQ5LUM9xPN5zWUxcNi5WPl83kdAAAtB8UJwDogPYeqlDqkq36ZP0BSVKgt4fuOruvrv6/7vK0WRvZGwAA/C+KEwB0IJVOl+Z/s1Pzv9mp6lq3rBbpylHdlHJ2X4X6282OBwBAu0VxAoAOoNLp0lvp2Xrp253Kc1RLkkb16KKZ4wfqlBgWrgUA4ERRnACgHSutqtGCH/fo1e9262C5U5IUG+yj+84foPMHRzFLHgAALYTiBADtUHGFU69/n6XXv98tR1WtJCmui49uPbO3LhkRK7sHEz8AANCSKE4A0I643IaeT9uuV5fvVll1XWHqFe6nqWf11h+HxsiDiR8AADgpKE4A0E44a926a+FafbKhbqa8/lEBuv13fXTuoCjZrFySBwDAyURxAoB2oLy6Vje/maHvthfK02bRrEuG6JIRsdzDBABAK6E4AUAbV1zh1JQ3VmlNdrF8vWx68ZoEndYn3OxYAAB0KhQnAGjDckuqNOm1ldqWV6ZgX0+9fu1IDe8WYnYsAAA6HYoTALRRWYXluvrVldp7qFKRgXYtuD5JfSMDzI4FAECnRHECgDZo836HJr2WrsKyasWH+mrB9UmK6+JrdiwAADotihMAtCHVtS7984csPZ+2Q2XVtRoYHah/XjdK4QF2s6MBANCpUZwAoA0wDEOfbDigWUu2au+hSklSUo8uenlyogK9PU1OBwAAKE4AYLKMPYf02CebtTq7WJIUEWDX3eP66dIRXVmfCQCANoLiBAAmySmq0KylW/XJ+roFbX08bbrpjJ668fSe8vXir2cAANoS/mUGgFbmcht65btd+vsX2+SsdctikS5L6Kq/ntNPkYHeZscDAABHQHECgFa052C57n5vnVZlHZIkje0dqvvPH6iBMYEmJwMAAMdCcQKAVmAYht5Kz9Zjn2xRhdMlf7uHZvxhoC5L7CqLhfuYAABo6yhOAHCS5Tmq9Lf31+ubbQWS6mbLe/qyoazLBABAO0JxAoCT6KN1+/XghxtVUlkjLw+r7j23v6aMiZeV2fIAAGhXKE4AcBLsK67UzP9u0pdb8iRJg2OD9MzlQ9UnMsDkZAAAoDkoTgDQgmpdbr3+fZae/XKbKpwuedosuvXM3rrtd73labOaHQ8AADQTxQkAWsia7EO674ON2nLAIUkaFd9Fj108iLNMAAB0ABQnADhBjqoaPbU0U2+u3CPDkIJ9PXXfeQP0p4Su3MsEAEAHQXECgGYyDEOfbsjVQx9vUkFptSTp0hFddd/5/RXqbzc5HQAAaEkUJwBohjxHlR74cKO+2Fw3+UPPcD89dtFgje4VanIyAABwMlCcAOA4GIahd1bl6PFPt6i0qlaeNotuObO3pp7VS3YPm9nxAADASUJxAoAmyios17RF6/XjriJJ0tC4YD156RD1i2LyBwAAOjrT58adO3eu4uPj5e3traSkJKWnpx9zfHFxsaZOnaro6GjZ7Xb17dtXn376aSulBdAZ1brcevGbnRo3+1v9uKtIPp42PfiHgVp0yxhKEwAAnYSpZ5wWLlyolJQUzZ8/X0lJSZo9e7bGjRunzMxMRUREHDbe6XTq7LPPVkREhN5//33FxsZqz549Cg4Obv3wADo8wzC0LLNAj3+6RdvzyyRJp/YOU+olgxXXxdfkdAAAoDVZDMMwzPrlSUlJGjlypObMmSNJcrvdiouL0+23365p06YdNn7+/Pl66qmntHXrVnl6ejbrdzocDgUFBamkpESBgYEnlB9Ax7VxX4ke/3SLfth5UFLdFOP3n183xbjFwhTjAAB0BMfTDUy7VM/pdCojI0PJycm/hrFalZycrBUrVhxxn48++kijR4/W1KlTFRkZqUGDBunxxx+Xy+U66u+prq6Ww+Fo8ACAo9lfXKmUd9dq/Jzl+mHnQXnZrLrp9J765p6zdFliHKUJAIBOyrRL9QoLC+VyuRQZGdlge2RkpLZu3XrEfXbt2qWvvvpKEydO1KeffqodO3bo1ltvVU1NjWbOnHnEfVJTU/Xwww+3eH4AHYujqkbzl+3Uq8t3q7rWLUm6cFiM7j6nH5flAQCA9jWrntvtVkREhF566SXZbDYlJCRo3759euqpp45anKZPn66UlJT65w6HQ3Fxca0VGUAbV1Zdq3/+kKWXvt2lksoaSVJSjy66/4IBGtI12NxwAACgzTCtOIWFhclmsykvL6/B9ry8PEVFRR1xn+joaHl6espm+3WtlAEDBig3N1dOp1NeXl6H7WO322W321s2PIB2r8JZq3+t2KMXv9mpQxV1halXuJ+mnTdAyQMiuCQPAAA0YNo9Tl5eXkpISFBaWlr9NrfbrbS0NI0ePfqI+4wdO1Y7duyQ2+2u37Zt2zZFR0cfsTQBwP+qdLr08re7dNoTX2vWkq06VFGjnmF+eu6KYfr8rjN09sBIShMAADiMqZfqpaSkaPLkyUpMTNSoUaM0e/ZslZeXa8qUKZKkSZMmKTY2VqmpqZKkW265RXPmzNEdd9yh22+/Xdu3b9fjjz+uv/zlL2Z+DADtgGEYevenHD312TYVllVLkrqH+uovv+ujC4fFyMNm+rJ2AACgDTO1OE2YMEEFBQWaMWOGcnNzNWzYMC1durR+wojs7GxZrb9+mYmLi9Nnn32mu+66S0OGDFFsbKzuuOMO3XvvvWZ9BADtQHWtSzM+3KSFP+VIkrqG+Ogvv++ji4fHypPCBAAAmsDUdZzMwDpOQOdSUFqtm9/MUMaeQ7JYpLvP6acbTuspLw8KEwAAnd3xdIN2NaseAByPDXtLdOOCn3SgpEoB3h564crhOrNfhNmxAABAO0RxAtAh/XftPv3t/fWqrnWrZ7ifXp6UqF7h/mbHAgAA7RTFCUCH4nIbeuqzTM3/Zqck6ax+4XruyuEK9PY0ORkAAGjPKE4AOoyicqdS3l2rZZkFkqRbzuylu8/pJ5uV6cUBAMCJoTgB6BBW7DyoOxeuUZ6jWnYPq5780xBdOCzW7FgAAKCDoDgBaNdqXW49/9UOvfDVdhmG1DPcT3OuHKGBMcyaCQAAWg7FCUC7tb+4Une+s1bpWUWSpMsTu+qhP54iXy/+agMAAC2LbxcA2qUvNufpnvfXqbiiRn5eNj1+yWAuzQMAACcNxQlAu1JSWaO/f56pf63YI0kaHBukF64crvgwP5OTAQCAjoziBKBdcNa6teDHPXrhq+0qrqiRJP351B7627n95eVhNTkdAADo6ChOANo0wzD0yYYDenJpprKLKiRJvSP8NeMPA3V633CT0wEAgM6C4gSgzVqVVaTHPtmitTnFkqQwf7v+ek5fXZbQVR42zjIBAIDWQ3EC0OYUlTt1/wcbtGRjriTJx9OmG0/vqRtP7yk/O39tAQCA1sc3EABtysZ9JbppQYb2FVfKapEmjIzTXcl9FRHobXY0AADQiVGcALQZ/127T/f+Z72qatyKD/XVPyYmsJAtAABoEyhOAExX63IrdclWvbp8tyTprH7hmn3FcAX5eJqcDAAAoA7FCYCpisqduu2t1fph50FJ0m1n9dZdZ/eVzWoxORkAAMCvKE4ATPPb+5l8vWx65vKhOndQtNmxAAAADkNxAtDqDMPQ2+k5emTxpvr7mV6alKi+kQFmRwMAADgiihOAVlVU7tS0/6zX55vzJHE/EwAAaB8oTgBazfLthUp5d63yS6vlabPo3nP767qxPWTlfiYAANDGUZwAnHTVtS49/VmmXv6ubta8XuF+ev7K4TolJsjkZAAAAE1DcQJwUu3IL9Vf3l6rzQcckqSr/6+b7j9/oHy8bCYnAwAAaDqKE4CTorSqRq8u36353+xUVY1bIb6eevJPQ3X2wEizowEAABw3ihOAFlVV49KbP+7R3K936FBFjSTptD5h+vtlQxUR6G1yOgAAgOahOAFoETUut97P2KvnvtyuXEeVJKlnmJ9Szumr8wdFMwEEAABo1yhOAE6I221o8YYDevaLbdpdWC5Jigny1p3JfXXJiFh52KwmJwQAADhxLVKcXC6XNmzYoO7duyskJKQl3hJAO5BVWK6/vb9e6VlFkqRQPy9NPau3rkrqJm9PJn8AAAAdR7OK05133qnBgwfr+uuvl8vl0hlnnKEffvhBvr6+Wrx4sc4888wWjgmgLXG7Df1zRZaeWLpVVTVu+XrZdMsZvTTl1B7yt3MiGwAAdDzN+obz/vvv6+qrr5Ykffzxx9q9e7e2bt2qBQsW6P7779f333/foiEBtB17DpbrnvfXK3133VmmMb1C9cSlQxTXxdfkZAAAACdPs4pTYWGhoqKiJEmffvqpLrvsMvXt21fXXXednnvuuRYNCKBtcLsN/WtFlp5YmqnKGpd8vWyafv4ATRzVjYkfAABAh9es4hQZGanNmzcrOjpaS5cu1bx58yRJFRUVstm4rwHoaHYVlGnaog2cZQIAAJ1Ws4rTlClTdPnllys6OloWi0XJycmSpJUrV6p///4tGhCAeYornHoubbsWrNijWrfBWSYAANBpNas4PfTQQxo0aJBycnJ02WWXyW63S5JsNpumTZvWogEBtD5nrVsLftyj59O2q6SybhHbM/uF69ELB3GWCQAAdEoWwzCMlnij4uJiBQcHt8RbnVQOh0NBQUEqKSlRYGCg2XGANsUwDH22KU+zlmxR1sEKSVL/qADdf8EAndYn3OR0AAAALet4ukGzVqZ84okntHDhwvrnl19+uUJDQ9W1a1etX7++OW8JwGSb9pdowos/6uY3M5R1sEJh/nbNumSwPvnLaZQmAADQ6TWrOM2fP19xcXGSpC+++EJffPGFlixZonPPPVd33333cb/f3LlzFR8fL29vbyUlJSk9Pf2oY9944w1ZLJYGD29v7+Z8DACqO8v0+ve7ddHc75WeVSS7h1W3/663lt1zpq4Y1U027mUCAABo3j1Oubm59cVp8eLFuvzyy3XOOecoPj5eSUlJx/VeCxcuVEpKiubPn6+kpCTNnj1b48aNU2ZmpiIiIo64T2BgoDIzM+ufWyx8sQOao6SiRn/7zzp9tilPknT2wEg9/MdTFBPsY3IyAACAtqVZZ5xCQkKUk5MjSVq6dGn9rHqGYcjlch3Xez3zzDO64YYbNGXKFA0cOFDz58+Xr6+vXnvttaPuY7FYFBUVVf+IjIxszscAOrW1OcW64IXv9NmmPHnaLJo5fqBeuiaB0gQAAHAEzSpOl1xyia666iqdffbZOnjwoM477zxJ0po1a9S7d+8mv4/T6VRGRkZ98ZIkq9Wq5ORkrVix4qj7lZWVqXv37oqLi9OFF16oTZs2NedjAJ2SYRh65btd+tO8H7T3UKW6dfHVf24Zoylje3D2FgAA4Ciadanes88+q/j4eOXk5OjJJ5+Uv7+/JOnAgQO69dZbm/w+hYWFcrlch50xioyM1NatW4+4T79+/fTaa69pyJAhKikp0dNPP60xY8Zo06ZN6tq162Hjq6urVV1dXf/c4XA0OR/Q0RRXOHX3e+v15Za6S/POHxylWZcOUaC3p8nJAAAA2rZmFSdPT88jTgJx1113nXCgxowePVqjR4+ufz5mzBgNGDBAL774oh599NHDxqempurhhx8+6bmAtm5HfqmmvLFKOUWV8rJZ9eAfBujq/+vOWSYAAIAmaNalepK0YMECnXrqqYqJidGePXskSbNnz9Z///vfJr9HWFiYbDab8vLyGmzPy8tTVFRUk97D09NTw4cP144dO474+vTp01VSUlL/+OXeLKAz+WFnoS75xw/KKaq7NG/RrWN0zeh4ShMAAEATNas4zZs3TykpKTrvvPNUXFxcPyFEcHCwZs+e3eT38fLyUkJCgtLS0uq3ud1upaWlNTirdCwul0sbNmxQdHT0EV+32+0KDAxs8AA6k/cz9mrSq+lyVNUqsXuIPpw6VoNig8yOBQAA0K40qzi98MILevnll3X//ffLZrPVb09MTNSGDRuO671SUlL08ssv65///Ke2bNmiW265ReXl5ZoyZYokadKkSZo+fXr9+EceeUSff/65du3apdWrV+vqq6/Wnj179Oc//7k5HwXosAzD0DOfZ+ru99ap1m1o/NAYvfnnJHXx8zI7GgAAQLvTrHucdu/ereHDhx+23W63q7y8/Ljea8KECSooKNCMGTOUm5urYcOGaenSpfUTRmRnZ8tq/bXfHTp0SDfccINyc3MVEhKihIQE/fDDDxo4cGBzPgrQIVXXunTv++v14dr9kqSpZ/XSX8/uJyuL2QIAADSLxTAM43h3GjhwoFJTU3XhhRcqICBA69atU8+ePfXCCy/o9ddf1+rVq09G1hbhcDgUFBSkkpISLttDh1Rc4dSNCzKUvrtIHlaLHrt4kCaM7GZ2LAAAgDbneLpBs844paSkaOrUqaqqqpJhGEpPT9fbb7+t1NRUvfLKK80KDeDEbcsr1U0LMrS7sFwBdg/NuzpBp/YJMzsWAABAu9es4vTnP/9ZPj4+euCBB1RRUaGrrrpKMTExeu6553TFFVe0dEYATfDRuv269/31qqxxKTbYR69dO1L9ogLMjgUAANAhNOtSvd+qqKhQWVmZIiIiWirTScWleuhoalxupX66Va99v1uSdGrvMD1/5XAmgQAAAGjESb9U77d8fX3l6+t7om8DoBnyHVWa+tZqrco6JKluEoiUs/vJxiQQAAAALapZ05Hn5eXpmmuuUUxMjDw8PGSz2Ro8AJx86buLdMELy7Uq65AC7B566ZoE3TOuP6UJAADgJGjWGadrr71W2dnZevDBBxUdHS2LhS9qQGsxDEOvfZ+lxz/dIpfbUL/IAM2/JkE9wvzMjgYAANBhNas4LV++XN99952GDRvWwnEAHIvLbWjmRxv15o/ZkqQLh8Uo9ZLB8vU64atuAQAAcAzN+rYVFxenE5xTAsBxqqpx6S9vr9Hnm/NksUgPXDBQ142N54wvAABAK2jWPU6zZ8/WtGnTlJWV1cJxABzJoXKnJr6yUp9vzpOXh1X/uGqErj+1B6UJAACglTTrjNOECRNUUVGhXr16ydfXV56eng1eLyoqapFwAKScogpNfj1duwrKFejtoVcmj9SoHl3MjgUAANCpNKs4Pfvss/yXbqAVbNpfomtfX6WC0mrFBHnrjetGqW8ki9oCAAC0tmbPqgfg5Ppue4FueXO1yqpr1T8qQG9MGaWoIG+zYwEAAHRKzbrHyWazKT8//7DtBw8eZB0noAV8vG6/pry+SmXVtRrdM1Tv3jya0gQAAGCiZp1xOtqMetXV1fLy8jqhQEBn9++Ve/TAhxtlGNIfhkTr75cPld2D/yABAABgpuMqTs8//7wkyWKx6JVXXpG/v3/9ay6XS99++6369+/fsgmBTuQfy3boyaWZkqSJSd30yIWDZLNyPyEAAIDZjqs4Pfvss5LqzjjNnz+/wWV5Xl5eio+P1/z581s2IdAJGIahWUu36sVvdkmSbj2zl+4Z149JWAAAANqI4ypOu3fvliSdddZZWrRokUJCQk5KKKAzcbkNPfDhRr2dni1Jmn5ef910Ri+TUwEAAOC3mnWP09dff93SOYBOyVnrVsq7a7V4/QFZLFLqxYN1xahuZscCAADA/2hycUpJSdGjjz4qPz8/paSkHHPsM888c8LBgI6u0unSLf/O0LLMAnnaLJo9YbguGBJtdiwAAAAcQZOL05o1a7R161YNHz5ca9asOeo47skAGldc4dT1//xJGXsOydvTqvlXJ+jMfhFmxwIAAMBRNLk4ff3117LZbDpw4ED9pXoTJkzQ888/r8jIyJMWEOhoDpRUavJr6dqWV6ZAbw+9du1IJcZ3MTsWAAAAjuG47nH63/WblixZovLy8hYNBHRkOwvKNOnVdO0rrlRkoF3/ui5J/aICzI4FAACARjRrcohfHG0hXACHW5dTrClvrFJRuVM9w/z0r+tHqWuIr9mxAAAA0ATHVZwsFsth9zBxTxPQuO+2F+imBRmqcLo0pGuQXr92pEL97WbHAgAAQBMd96V61157rez2ui98VVVVuvnmm+Xn59dg3KJFi1ouIdDOfbRuv/767lrVuAyd2jtM869JkL/9hE72AgAAoJUd17e3yZMnN3h+9dVXt2gYoCMxDEOvfLdbjy/ZIsOQ/jAkWn+/fKjsHjazowEAAOA4HVdxev31109WDqBDqapx6b5FG7RozT5J0qTR3TVz/CmyWbm0FQAAoD3ieiGgheU5qnTjggytyymWzWrRgxcM0OQx8dwPCAAA0I5RnIAWtCb7kG5akKH80moF+3pq7lUjNLZ3mNmxAAAAcIIoTkAL+U/GXk3/YIOctW71jfTXy5MS1T3Ur/EdAQAA0OZRnIATVOtya9aSrXpl+W5J0tkDI/XshGHMnAcAANCB8M0OOAGFZdW64501+n7HQUnSX37XW3cm95WVSSAAAAA6FIoT0Ezpu4t021urlV9aLR9Pm56+bKguGBJtdiwAAACcBBQn4DgZhqGXvt2lJz/LlMttqHeEv+ZNHKE+kQFmRwMAAMBJQnECjkNJZY3ufm+dvticJ0m6aFiMHrt4sPy4nwkAAKBD49se0EQb9pbo1rcylFNUKS+bVTPGD9TEpG6szwQAANAJUJyARhiGoTd/3KNHF2+R0+VW1xAfzZuYoMFdg8yOBgAAgFZiNTuAJM2dO1fx8fHy9vZWUlKS0tPTm7TfO++8I4vFoosuuujkBkSnVVTu1A3/ytCD/90kp8ut5AGR+uT20yhNAAAAnYzpxWnhwoVKSUnRzJkztXr1ag0dOlTjxo1Tfn7+MffLysrS3XffrdNOO62VkqKzWb69UOfO/lZfbsmTl82qBy4YoJeuSVCQr6fZ0QAAANDKTC9OzzzzjG644QZNmTJFAwcO1Pz58+Xr66vXXnvtqPu4XC5NnDhRDz/8sHr27NmKadEZOGvdSv10i65+daXyS6vVK9xPH0wdoz+f1pP1mQAAADopU4uT0+lURkaGkpOT67dZrVYlJydrxYoVR93vkUceUUREhK6//vpGf0d1dbUcDkeDB3A0OwvKdMm87/Xit7skSVclddPi20/TKTFcmgcAANCZmTo5RGFhoVwulyIjIxtsj4yM1NatW4+4z/Lly/Xqq69q7dq1Tfodqampevjhh080KjqBD9bs1X2LNqqyxqVgX0/NumSIzh0UZXYsAAAAtAGmX6p3PEpLS3XNNdfo5ZdfVlhYWJP2mT59ukpKSuofOTk5Jzkl2qNFq/fqroXrVFnj0uieoVp6x+mUJgAAANQz9YxTWFiYbDab8vLyGmzPy8tTVNThX1p37typrKwsjR8/vn6b2+2WJHl4eCgzM1O9evVqsI/dbpfdbj8J6dFRLN2Yq3veXy9JmjS6u2aOP0U27mUCAADAb5h6xsnLy0sJCQlKS0ur3+Z2u5WWlqbRo0cfNr5///7asGGD1q5dW//44x//qLPOOktr165VXFxca8ZHB/Dd9gL95e01crkNXTqiqx6iNAEAAOAITF8ANyUlRZMnT1ZiYqJGjRql2bNnq7y8XFOmTJEkTZo0SbGxsUpNTZW3t7cGDRrUYP/g4GBJOmw70Jifsop0478y5HS5dd6gKD1x6WBmzQMAAMARmV6cJkyYoIKCAs2YMUO5ubkaNmyYli5dWj9hRHZ2tqzWdnUrFtqBjftKNOWNVaqscen0vuGafcUwedg4zgAAAHBkFsMwDLNDtCaHw6GgoCCVlJQoMDDQ7DgwwY78Ml3+4goVlTs1Kr6L/nndKPl42cyOBQAAgFZ2PN2A/8SOTiWnqEJXv7JSReVODYoN1CvXJlKaAAAA0CiKEzqNfEeVrn51pXIdVeoT4a9/XZekQG9Ps2MBAACgHaA4oVMornDqmlfTtedgheK6+GjB9Unq4udldiwAAAC0ExQndHhl1bWa/PoqZeaVKiLArn9f/3+KCvI2OxYAAADaEYoTOrSqGpdu/NdPWpdTrGBfT7355yR1C/U1OxYAAADaGYoTOqwal1u3vbVGP+w8KH+7h/45ZZT6RgaYHQsAAADtEMUJHZLbbeie99bpyy15sntY9crkRA2NCzY7FgAAANopihM6HMMwNPOjTfpw7X55WC2ad/UI/V/PULNjAQAAoB2jOKHDefrzTC34cY8sFumZCcP0u/6RZkcCAABAO0dxQofyyne7NPfrnZKkxy4arD8OjTE5EQAAADoCihM6jEWr9+r/fbJFkvS3c/vpqqRuJicCAABAR0FxQofw1dY83fP+eknSn0/toVvO6GVyIgAAAHQkFCe0exl7inTrv1fL5TZ0yfBY3Xf+AFksFrNjAQAAoAOhOKFd25ZXquve+ElVNW6d1S9cT/xpiKxWShMAAABaFsUJ7dbeQxWa9Gq6SiprNKJbsOZOHCFPG4c0AAAAWh7fMtEuHSyr1qRX05XrqFKfCH+9du1I+Xp5mB0LAAAAHRTFCe1OWXWtrntjlXYVlis22Ef/un6Ugn29zI4FAACADozihHalwlmrKa+na93eEoX4euqf141SdJCP2bEAAADQwVGc0G5UOl26/o2ftCrrkAK8PfSv65LUO8Lf7FgAAADoBChOaBeqaly6ccFPWrHroPztHvrXdaM0uGuQ2bEAAADQSVCc0OY5a9269d+r9d32Qvl62fT6lJEa3i3E7FgAAADoRChOaNNqXG7d/vZqfbU1X3YPq16ZnKiR8V3MjgUAAIBOhuKENqvW5dadC9fqs0158vKw6uVJiRrTK8zsWAAAAOiEKE5ok1xuQ/e8v16frD8gT5tFL16doNP7hpsdCwAAAJ0UxQltjmEYuv+DDfpgzT55WC2ac9UIndU/wuxYAAAA6MQoTmhTDMPQ//tki95ZlSOrRZp9xTCNOyXK7FgAAADo5ChOaFNmf7ldry7fLUmadekQ/WFIjMmJAAAAAIoT2pCXv92l59K2S5IeGj9QlyfGmZwIAAAAqENxQpvw1spsPfbpFknSPeP66dqxPUxOBAAAAPyK4gTTfbhmn+7/cIMk6ZYze2nqWb1NTgQAAAA0RHGCqT7blKu/vrdOhiFNGt1dfxvXz+xIAAAAwGEoTjDNDzsKdftba+RyG7p0RFc9NP4UWSwWs2MBAAAAh6E4wRQ78kt105sZcrrcOm9QlJ64dLCsVkoTAAAA2iaKE1rdwbJqXffGTyqtqlVi9xA9O2GYPGwcigAAAGi7+LaKVlVV49JNCzKUXVShbl189eI1CfL2tJkdCwAAADgmihNajWEYuvc/6/XTnkMK8PbQa9cmKtTfbnYsAAAAoFFtojjNnTtX8fHx8vb2VlJSktLT0486dtGiRUpMTFRwcLD8/Pw0bNgwLViwoBXTormeS9uu/67dLw+rRfOvTlDviACzIwEAAABNYnpxWrhwoVJSUjRz5kytXr1aQ4cO1bhx45Sfn3/E8V26dNH999+vFStWaP369ZoyZYqmTJmizz77rJWT43h8uGafZn+5XZL06EWDNLZ3mMmJAAAAgKazGIZhmBkgKSlJI0eO1Jw5cyRJbrdbcXFxuv322zVt2rQmvceIESN0wQUX6NFHH210rMPhUFBQkEpKShQYGHhC2dE0P2UV6aqXV8rpcuum03tq+vkDzI4EAAAAHFc3MPWMk9PpVEZGhpKTk+u3Wa1WJScna8WKFY3ubxiG0tLSlJmZqdNPP/2IY6qrq+VwOBo80HqyD1boxgV1046fMzBS957b3+xIAAAAwHEztTgVFhbK5XIpMjKywfbIyEjl5uYedb+SkhL5+/vLy8tLF1xwgV544QWdffbZRxybmpqqoKCg+kdcXFyLfgYcXVWNSze9maGicqcGxwZp9hXDWKsJAAAA7ZLp9zg1R0BAgNauXatVq1bpscceU0pKipYtW3bEsdOnT1dJSUn9Iycnp3XDdmKPLt6sLQcc6uLnpZcnJcrXy8PsSAAAAECzmPpNNiwsTDabTXl5eQ225+XlKSoq6qj7Wa1W9e7dW5I0bNgwbdmyRampqTrzzDMPG2u322W3M+V1a/t43X79e2W2JOnZCcMUFeRtciIAAACg+Uw94+Tl5aWEhASlpaXVb3O73UpLS9Po0aOb/D5ut1vV1dUnIyKaYXdhuaYv2iBJmnpWL53RN9zkRAAAAMCJMf3aqZSUFE2ePFmJiYkaNWqUZs+erfLyck2ZMkWSNGnSJMXGxio1NVVS3T1LiYmJ6tWrl6qrq/Xpp59qwYIFmjdvnpkfAz+rqnFp6r9Xq6y6VqPiu+iu5L5mRwIAAABOmOnFacKECSooKNCMGTOUm5urYcOGaenSpfUTRmRnZ8tq/fXEWHl5uW699Vbt3btXPj4+6t+/v958801NmDDBrI+A3/h/n2zW5p/va3r+yuHysLXL2+gAAACABkxfx6m1sY7TyfPxuv26/e01kqR/XjeKS/QAAADQprWbdZzQcWRxXxMAAAA6MIoTTlhVjUtT3+K+JgAAAHRcFCecEMMw9PDHm7RpP/c1AQAAoOPiGy5OyMvf7dLb6TmyWFivCQAAAB0XxQnNtnRjrlKXbJUkPXDBQO5rAgAAQIdFcUKzrMsp1p0L18gwpEmju+u6sfFmRwIAAABOGooTjtveQxW6/p8/qarGrTP7hWvGHwbKYrGYHQsAAAA4aShOOC6Oqhpd/8ZPKiyrVv+oAM25agSTQQAAAKDD4xsvmqzG5dbUf69WZl6pIgLseu3akfK3e5gdCwAAADjpKE5oEsMwNPOjTfpue6F8PG16dfJIxQT7mB0LAAAAaBUUJzTJq8t3662V2bJYpOevHK7BXYPMjgQAAAC0GooTGrU6+1CDacfPHhhpciIAAACgdVGccEyOqhrd8c4audyGxg+NYdpxAAAAdEoUJxyVYRh64IONyimqVNcQHz128SCmHQcAAECnRHHCUf1n9T59tG6/bFaLnr9yuAK9Pc2OBAAAAJiC4oQj2l1Yrhn/3ShJuiu5j0Z0CzE5EQAAAGAeihMO46x16y9vr1GF06X/69lFt5zZ2+xIAAAAgKkoTjjM3z/P1IZ9JQr29dSzE4bJZuW+JgAAAHRuFCc08O22Ar347S5J0hOXDlF0EIvcAgAAABQn1Cssq1bKu+skSROTumncKVEmJwIAAADaBooTJNVNPf6399ersKxafSL89cAFA82OBAAAALQZFCdIkt5Oz9FXW/Pl5WHV81cOl4+XzexIAAAAQJtBcYKyD1bo/32yWZJ0zzn9NCA60OREAAAAQNtCcerkXG5Dd7+3ThVOl0bFd9F1p/YwOxIAAADQ5lCcOrnXlu9WelaRfL1sevqyoUw9DgAAABwBxakT25ZXqqc+z5QkPXDBQHUL9TU5EQAAANA2UZw6qRqXWynvrpWz1q0z+4XrylFxZkcCAAAA2iyKUyc156sd2rjPoSAfTz1x6RBZLFyiBwAAABwNxakTWr+3WHO+3iFJeuTCUxQZ6G1yIgAAAKBtozh1MlU1LqW8u04ut6ELhkTrj0NjzI4EAAAAtHkUp07m6c8ytSO/TOEBdv2/CwdxiR4AAADQBBSnTuTHXQf16ve7JUlPXDpYIX5eJicCAAAA2geKUydRWlWjv767ToYhTUiM0+/6R5odCQAAAGg3KE6dxKOLN2tfcaW6hvjowfEDzY4DAAAAtCsUp07g8025evenvbJYpGcuHyZ/u4fZkQAAAIB2heLUwRWWVWv6og2SpBtP66lRPbqYnAgAAABof9pEcZo7d67i4+Pl7e2tpKQkpaenH3Xsyy+/rNNOO00hISEKCQlRcnLyMcd3ZoZh6L5FG3Sw3Kl+kQG66+y+ZkcCAAAA2iXTi9PChQuVkpKimTNnavXq1Ro6dKjGjRun/Pz8I45ftmyZrrzySn399ddasWKF4uLidM4552jfvn2tnLzt+8/qffp8c548bRY9M2GovD1tZkcCAAAA2iWLYRiGmQGSkpI0cuRIzZkzR5LkdrsVFxen22+/XdOmTWt0f5fLpZCQEM2ZM0eTJk1qdLzD4VBQUJBKSkoUGBh4wvnbqr2HKnTe7O9UWl2re8b109SzepsdCQAAAGhTjqcbmHrGyel0KiMjQ8nJyfXbrFarkpOTtWLFiia9R0VFhWpqatSly5Hv3amurpbD4Wjw6OjcbkP3vLdepdW1SugeopvP6GV2JAAAAKBdM7U4FRYWyuVyKTKy4ZpCkZGRys3NbdJ73HvvvYqJiWlQvn4rNTVVQUFB9Y+4uLgTzt3Wvf5DllbsOihfL5v+ftlQ2awWsyMBAAAA7Zrp9zidiFmzZumdd97RBx98IG9v7yOOmT59ukpKSuofOTk5rZyyde3IL9UTS7dKku6/YIDiw/xMTgQAAAC0f6Yu6BMWFiabzaa8vLwG2/Py8hQVFXXMfZ9++mnNmjVLX375pYYMGXLUcXa7XXa7vUXytnW1Lrf++u46OWvdOqNvuK4a1c3sSAAAAECHYOoZJy8vLyUkJCgtLa1+m9vtVlpamkaPHn3U/Z588kk9+uijWrp0qRITE1sjarvw4re7tG5viQK9PfTEpUNksXCJHgAAANASTD3jJEkpKSmaPHmyEhMTNWrUKM2ePVvl5eWaMmWKJGnSpEmKjY1VamqqJOmJJ57QjBkz9NZbbyk+Pr7+Xih/f3/5+/ub9jnMtjXXodlfbpMkPfTHUxQVdORLFwEAAAAcP9OL04QJE1RQUKAZM2YoNzdXw4YN09KlS+snjMjOzpbV+uuJsXnz5snpdOpPf/pTg/eZOXOmHnroodaM3mbU/HyJXo3LUPKASF08PNbsSAAAAECHYvo6Tq2tI67j9OwX2/Rc2nYF+3rq87tOV0QAZ5sAAACAxrSbdZxw4jbuK9Hcr3dIkh69cBClCQAAADgJKE7tWHWtS399d51q3YbOHxylPwyJNjsSAAAA0CFRnNqx577crsy8UoX6eenRCwcxix4AAABwklCc2qk12Yc0/5udkqTHLh6sUP/OsVYVAAAAYAaKUztUVePSX99bJ7chXTgsRucOOvZiwQAAAABODMWpHZrz1Q7tKihXRIBdD//xFLPjAAAAAB0examd2ZFfqhe/rbtE75ELT1Gwr5fJiQAAAICOj+LUjhiGofs+2Kgal6Hf94/QuFO4RA8AAABoDRSnduS9jL1K310kH0+bHr7wFGbRAwAAAFoJxamdKCp3KvXTLZKkO5P7qGuIr8mJAAAAgM6D4tROpH66RYcqatQ/KkDXndrD7DgAAABAp0JxagdW7jqo9zL2Sqpbs8nTxv9tAAAAQGviG3gb56x16/4PN0qSrhzVTQndQ0xOBAAAAHQ+FKc27qVvd2pHfpnC/L007dz+ZscBAAAAOiWKUxu252C5XvhqhyTpgQsGKsjX0+REAAAAQOdEcWqjDMPQg//dpOpat07tHaYLh8WYHQkAAADotChObdQXm/P07bYCeXlY9ehFg1izCQAAADARxamNev37LEnSdWN7qEeYn7lhAAAAgE6O4tQG7cgv1YpdB2W1SJNGdzc7DgAAANDpUZzaoDd/zJYk/X5ApGKCfUxOAwAAAIDi1MZUOGv1n9V1i91e/X+cbQIAAADaAopTG/Pxuv0qrapV91BfndY7zOw4AAAAAERxalMMw9CCH/dIkiYmdZPVykx6AAAAQFtAcWpD1u0t0cZ9Dnl5WHVZQpzZcQAAAAD8jOLUhixYUXe26Q9DohXi52VyGgAAAAC/oDi1EcUVTi1ev18Sk0IAAAAAbQ3FqY14P2OvqmvdGhgdqOFxwWbHAQAAAPAbFKc2wO029ObPk0JcM7q7LBYmhQAAAADaEopTG/D9zkJlHaxQgN1DFw6LMTsOAAAAgP9BcWoDfjnbdMmIWPl6eZicBgAAAMD/ojiZ7EBJpb7YnCeJSSEAAACAtoriZLK303PkNqSkHl3UJzLA7DgAAAAAjoDiZKIal1vvpGdL4mwTAAAA0JZRnEz0xeY85ZdWK8zfrnGnRJkdBwAAAMBRUJxM9NHaugVvrxgZJy8P/q8AAAAA2iqmcDPRc1cO09KNuRrVo4vZUQAAAAAcg+mnOebOnav4+Hh5e3srKSlJ6enpRx27adMmXXrppYqPj5fFYtHs2bNbL+hJYPew6cJhsYoO8jE7CgAAAIBjMLU4LVy4UCkpKZo5c6ZWr16toUOHaty4ccrPzz/i+IqKCvXs2VOzZs1SVBT3BAEAAABoHaYWp2eeeUY33HCDpkyZooEDB2r+/Pny9fXVa6+9dsTxI0eO1FNPPaUrrrhCdru9ldMCAAAA6KxMK05Op1MZGRlKTk7+NYzVquTkZK1YsaLFfk91dbUcDkeDBwAAAAAcD9OKU2FhoVwulyIjIxtsj4yMVG5ubov9ntTUVAUFBdU/4uLiWuy9AQAAAHQOpk8OcbJNnz5dJSUl9Y+cnByzIwEAAABoZ0ybjjwsLEw2m015eXkNtufl5bXoxA92u537oQAAAACcENPOOHl5eSkhIUFpaWn129xut9LS0jR69GizYgEAAADAYUxdADclJUWTJ09WYmKiRo0apdmzZ6u8vFxTpkyRJE2aNEmxsbFKTU2VVDehxObNm+v/vG/fPq1du1b+/v7q3bu3aZ8DAAAAQMdmanGaMGGCCgoKNGPGDOXm5mrYsGFaunRp/YQR2dnZslp/PSm2f/9+DR8+vP75008/raefflpnnHGGli1b1trxAQAAAHQSFsMwDLNDtCaHw6GgoCCVlJQoMDDQ7DgAAAAATHI83aDDz6oHAAAAACeK4gQAAAAAjaA4AQAAAEAjKE4AAAAA0AhTZ9Uzwy9zYTgcDpOTAAAAADDTL52gKfPldbriVFpaKkmKi4szOQkAAACAtqC0tFRBQUHHHNPppiN3u93av3+/AgICZLFYzI4jh8OhuLg45eTkMD06mozjBs3BcYPm4thBc3DcoDla+7gxDEOlpaWKiYlpsH7skXS6M05Wq1Vdu3Y1O8ZhAgMD+UsFx43jBs3BcYPm4thBc3DcoDla87hp7EzTL5gcAgAAAAAaQXECAAAAgEZQnExmt9s1c+ZM2e12s6OgHeG4QXNw3KC5OHbQHBw3aI62fNx0uskhAAAAAOB4ccYJAAAAABpBcQIAAACARlCcAAAAAKARFCcAAAAAaATFyURz585VfHy8vL29lZSUpPT0dLMjoQ1JTU3VyJEjFRAQoIiICF100UXKzMxsMKaqqkpTp05VaGio/P39demllyovL8+kxGiLZs2aJYvFojvvvLN+G8cNjmbfvn26+uqrFRoaKh8fHw0ePFg//fRT/euGYWjGjBmKjo6Wj4+PkpOTtX37dhMTw2wul0sPPvigevToIR8fH/Xq1UuPPvqofjv3GMcNJOnbb7/V+PHjFRMTI4vFog8//LDB6005ToqKijRx4kQFBgYqODhY119/vcrKylrtM1CcTLJw4UKlpKRo5syZWr16tYYOHapx48YpPz/f7GhoI7755htNnTpVP/74o7744gvV1NTonHPOUXl5ef2Yu+66Sx9//LHee+89ffPNN9q/f78uueQSE1OjLVm1apVefPFFDRkypMF2jhscyaFDhzR27Fh5enpqyZIl2rx5s/7+978rJCSkfsyTTz6p559/XvPnz9fKlSvl5+encePGqaqqysTkMNMTTzyhefPmac6cOdqyZYueeOIJPfnkk3rhhRfqx3DcQJLKy8s1dOhQzZ0794ivN+U4mThxojZt2qQvvvhCixcv1rfffqsbb7yxtT6CZMAUo0aNMqZOnVr/3OVyGTExMUZqaqqJqdCW5efnG5KMb775xjAMwyguLjY8PT2N9957r37Mli1bDEnGihUrzIqJNqK0tNTo06eP8cUXXxhnnHGGcccddxiGwXGDo7v33nuNU0899aivu91uIyoqynjqqafqtxUXFxt2u914++23WyMi2qALLrjAuO666xpsu+SSS4yJEycahsFxgyOTZHzwwQf1z5tynGzevNmQZKxatap+zJIlSwyLxWLs27evVXJzxskETqdTGRkZSk5Ort9mtVqVnJysFStWmJgMbVlJSYkkqUuXLpKkjIwM1dTUNDiO+vfvr27dunEcQVOnTtUFF1zQ4PiQOG5wdB999JESExN12WWXKSIiQsOHD9fLL79c//ru3buVm5vb4NgJCgpSUlISx04nNmbMGKWl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",
      "text/plain": [
       "<Figure size 1000x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(10,5))\n",
    "plt.xlabel(\"Generations\")\n",
    "plt.ylabel(\"Fitness\")\n",
    "plt.plot(pop_fit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [],
   "source": [
    "pop.sort(key=lambda x: x.fitness, reverse=True) #sort in place, highest fitness first"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Hllolo Wrld!'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "pop[0].string"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.12"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
